/**
 * 
 */
package com.netscenery.yang.model;

import java.util.ArrayList;

import org.jdom2.Attribute;
import org.jdom2.Element;

import com.netscenery.util.ErrTag;
import com.netscenery.util.QName;
import com.netscenery.util.Unicode;
import com.netscenery.util.XMLTag;
import com.netscenery.yang.YangKeyword;
import com.netscenery.yang.YangStatement;
import com.netscenery.yang.designer.MapInfo;
import com.netscenery.yang.parser.YangParserException;

/**
 * @author llly
 *
 */
public class Feature extends Entity {
	private ArrayList<String> if_features;
	
	
	public Feature(Env env,String name){
		this.setEnv(env);
		this.setName(name);
	}

	public boolean checkIf_feature(String feature){
		if (null == feature){
			return false;
		}
		Module m = env.getCurModule();
		if (null == m){
			return false;
		}
		QName qFeature = new QName(feature);
		if (qFeature.isQName()){
			String prefix = qFeature.getPrefix();
			String localName = qFeature.getLocalName();
			if (null == prefix || null == localName){
				return false;
			}
			Module imp = m.getModule(prefix);
			if (null == imp ){
				return false;
			}
			
			if (null == imp.getFeature(localName)){
				return false;
			}
	
		}
		else {
			if (null == m.getFeature(feature)){
				return false;
			}
		}
		return true;
	}
	public boolean addIf_feature(String feature){
		if (null == feature){
			return false;
		}
		//TODO validate feature's name
		if (false == checkIf_feature(feature)){
			return false;
		}
		if (null == if_features){
			if_features = new ArrayList<String>(1);
		}
		return if_features.add(feature);
	}
	
	public String getIf_feature(int index){
		if (null == if_features){
			return null;
		}
		return if_features.get(index);
	}
	
	public String removeIf_feature(int index){
		if (null == if_features){
			return null;
		}
		return if_features.remove(index);
	}
	
	public int getIf_featuresNumber(){
		if (null == if_features){
			return 0;
		}
		
		return if_features.size();
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#validate()
	 */
	@Override
	public Validator validate() {
		Validator validator = new Validator();
		if(!checkName(this.name)){
			validator.setIsValid(false);
			validator.addMsg(new Message(this,ErrTag.ERROR,ErrorCode.COMMON_INVALIDNAME));
		}
		if (null != if_features){
			int size = getIf_featuresNumber();
			Module m = env.getCurModule();
			if (null == m ){
				validator.setIsValid(false);
				validator.addMsg(new Message(this,ErrTag.ERROR,ErrorCode.COMMON_ERROR));
			}
			
			ArrayList<String> featureList = m.getAvailableFeatureNames();
			if (null == featureList){
				validator.setIsValid(false);
				validator.addMsg(new Message(this,ErrTag.ERROR,"there is no available features."));
			}
			else {
				for (int i = 0; i < size ;i++){								
					String feature = getIf_feature(i);
					if (null == feature){
						continue;
					}
					if (!featureList.contains(feature)){
						validator.setIsValid(false);
						validator.addMsg(new Message(this,ErrTag.ERROR,"invalid featurename."));
					}
				}
			}
			
			
		}
		if (!isNullString(this.description)){
			if (Unicode.containChinese(this.description)){
				validator.setIsValid(false);
				validator.addMsg(new Message(this,ErrTag.ERROR,"description",ErrorCode.INVALID_CHARACTER));
			}
		}
		
		if (!isNullString(this.reference)){
			if (Unicode.containChinese(this.reference)){
				validator.setIsValid(false);
				validator.addMsg(new Message(this,ErrTag.ERROR,"reference",ErrorCode.INVALID_CHARACTER));
			}
		}
		
		Validator sValidator = super.validate();
		validator.copy(sValidator);
		return validator;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#toYang()
	 */
	@Override
	public YangStatement toYang() {

		YangStatement statement = new YangStatement(YangStatement.YANG_STATEMENT_FEATURE
				,this.getName());
		if (null != this.if_features){
			int size = this.getIf_featuresNumber();
			
			for (int i = 0; i < size; i++){
				String feature = this.getIf_feature(i);
				if (null != feature){
					YangStatement  featureState = 
							new YangStatement(
									YangStatement.YANG_STATEMENT_IFFEATURE
							        ,feature);
					statement.addChild(featureState);
				}
			}
			
		}
		if (null != this.getDescription()){
			YangStatement descr = new YangStatement(YangStatement.YANG_STATEMENT_DESCRIPTION
					,this.getDescription());
			statement.addChild(descr);
			
		}
		
		if (null != this.getReference()){
			YangStatement ref = new YangStatement(YangStatement.YANG_STATEMENT_REFERENCE
					,this.getReference());
			statement.addChild(ref);
		}
		
		if (Status.CURRENT != this.getStatus()){
			YangStatement status = new YangStatement(YangStatement.YANG_STATEMENT_STATUS
					,this.getStatus().getStatus());
			statement.addChild(status);
		}

		
		return statement;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#toXML()
	 */
	@Override
	public Element toXML() {

		Element element = new Element(XMLTag.XML_TAG_FEATURE);
		Element name = new Element(XMLTag.XML_TAG_NAME);
		name.setText(this.getName());
		element.addContent(name);

		if (null != this.if_features){
			int size = this.getIf_featuresNumber();
			
			for (int i = 0; i < size; i++){
				String feature = this.getIf_feature(i);
				if (null != feature){
					Element  featureState = 
							new Element(XMLTag.XML_TAG_IFFEATURE);
					featureState.addContent(feature);
					element.addContent(featureState);
				}
			}
			
		}
		if (null != this.getDescription()){
			Element descr = new Element(XMLTag.XML_TAG_DESCRIPTION);
			descr.setText(getDescription());
			element.addContent(descr);
			
		}
		
		if (null != this.getReference()){
			Element ref = new Element(XMLTag.XML_TAG_REFERENCE);
			ref.setText(getReference());
			element.addContent(ref);
		}
		
		//if (Status.CURRENT != this.getStatus()){
			Element status = new Element(XMLTag.XML_TAG_STATUS);
			status.setText(this.getStatus().getStatus());
			element.addContent(status);
		//}
		
		return element;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#isFieldMandatory(java.lang.String)
	 */
	@Override
	public boolean isFieldMandatory(String field) {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#readXML(org.jdom2.Element)
	 */
	@Override
	public int readXML(Element element) throws ModelException {
		if (null == element){
			return MODELELEMENT_OK;
		}

		String value = element.getText();

		// ����
		if (element.getName().equals(
				XMLTag.XML_TAG_DESCRIPTION)) {
			this.setDescription(value);
		}
		// reference
		else if (element.getName().equals(
				XMLTag.XML_TAG_REFERENCE)) {
			this.setReference(value);
		}
		// status
		else if (element.getName().equals(
				XMLTag.XML_TAG_STATUS)) {
			this.setStatus(Status.getStatus(value));
		}
		// if_feature
		else if (element.getName().equals(
				XMLTag.XML_TAG_IFFEATURE)) {
			this.addIf_feature(value);
		}
		else if (element.getName().equals(
				XMLTag.XML_TAG_NAME)){
			return MODELELEMENT_OK;
		}
		// ������ֶ�
		else {
			return MODELELEMENT_FAIL;
		}

		return MODELELEMENT_OK;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#readYANG(com.netscenery.modeldesigner.util.YangStatement)
	 */
	@Override
	public int readYANG(YangStatement statement) throws YangParserException {
		if (null == statement){
			return MODELELEMENT_OK;
		}
		


		String value = statement.getArgument();

		// ����
		if (statement.getKeyword().equals(
				YangStatement.YANG_STATEMENT_DESCRIPTION)) {
			this.setDescription(value);
		}
		// reference
		else if (statement.getKeyword().equals(
				YangStatement.YANG_STATEMENT_REFERENCE)) {
			this.setReference(value);
		}
		// status
		else if (statement.getKeyword().equals(
				YangStatement.YANG_STATEMENT_STATUS)) {
			this.setStatus(Status.getStatus(value));
		}
		// if-feature
		else if (statement.getKeyword().equals(
				YangStatement.YANG_STATEMENT_IFFEATURE)) {
			this.addIf_feature(value);
		}
		// ������ֶ�
		else {
			return MODELELEMENT_FAIL;
		}

		return MODELELEMENT_OK;
	}

	@Override
	public MapInfo getMapInfo() throws SecurityException, NoSuchMethodException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Element toYin() {
		Element statement = new Element(YangStatement.YANG_STATEMENT_FEATURE,env.getNs());
		Attribute name = new Attribute(XMLTag.XML_TAG_NAME,this.getName());
		statement.setAttribute(name);
		if (null != this.if_features){
			int size = this.getIf_featuresNumber();
			
			for (int i = 0; i < size; i++){
				String feature = this.getIf_feature(i);
				if (null != feature){
					Element  featureState = new Element(YangStatement.YANG_STATEMENT_IFFEATURE,env.getNs());
					Attribute af = new Attribute(XMLTag.XML_TAG_NAME,feature);
					featureState.setAttribute(af);
					statement.addContent(featureState);
				}
			}
			
		}
		if (!isNullString(this.getDescription())){
			Element descr = new Element(YangStatement.YANG_STATEMENT_DESCRIPTION,env.getNs());
			Element text = new Element(XMLTag.XML_TAG_TEXT,env.getNs());
			text.setText(this.getDescription());
			descr.addContent(text);
			statement.addContent(descr);
			
		}
		
		if (!isNullString(this.getReference())){
			Element ref = new Element(YangStatement.YANG_STATEMENT_REFERENCE,env.getNs());
			Element text = new Element(XMLTag.XML_TAG_TEXT,env.getNs());
			text.setText(this.getReference());
			ref.addContent(text);
			statement.addContent(ref);
		}
		
		if (Status.CURRENT != this.getStatus()){
			Element status = new Element(YangStatement.YANG_STATEMENT_STATUS,env.getNs());
			Attribute value = new Attribute(YangKeyword.VALUE.getKeyword(),this.getStatus().getStatus());
			status.setAttribute(value);
			statement.addContent(status);
		}

		
		return statement;
	}

	@Override
	public int readYin(Element statement) throws ModelException {
		if (null == statement){
			return MODELELEMENT_OK;
		}
		// ����
		if (statement.getName().equals(YangStatement.YANG_STATEMENT_DESCRIPTION)) {
			Element text = statement.getChild(XMLTag.XML_TAG_TEXT,env.getNs());
			if (null == text){
				return MODELELEMENT_FAIL;
			}
			this.setDescription(text.getText());
		}
		// reference
		else if (statement.getName().equals(
				YangStatement.YANG_STATEMENT_REFERENCE)) {
			Element text = statement.getChild(XMLTag.XML_TAG_TEXT,env.getNs());
			if (null == text){
				return MODELELEMENT_FAIL;
			}
			this.setReference(text.getText());
		}
		// status
		else if (statement.getName().equals(
				YangStatement.YANG_STATEMENT_STATUS)) {
			String value= statement.getAttributeValue(YangKeyword.VALUE.getKeyword());
			if (null == value){
				return MODELELEMENT_FAIL;
			}
			else {
				this.status = Status.getStatus(value);
			}
		}
	
		// if-feature
		else if (statement.getName().equals(
				YangStatement.YANG_STATEMENT_IFFEATURE)) {
			String value= statement.getAttributeValue(XMLTag.XML_TAG_NAME);
			if (null == value){
				return MODELELEMENT_FAIL;
			}
			else {
				this.addIf_feature(value);
			}
			
		}
		// ������ֶ�
		else {
			return MODELELEMENT_FAIL;
		}

		return MODELELEMENT_OK;
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		
	}

}
